package com.myk.game.sumeru.pages;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;

import com.myk.game.lib.DrawBuffer;
import com.myk.game.lib.OnRecyclerItemDownListener;
import com.myk.game.lib.SimpleAdapter;
import com.myk.game.lib.utils.BitmapUtil;
import com.myk.game.sumeru.R;
import com.myk.game.sumeru.game.Chess;
import com.myk.game.sumeru.game.Grid;
import com.myk.game.sumeru.game.PersonalGame;
import com.myk.game.sumeru.game.RobotGame;
import com.myk.game.sumeru.interfaces.IGame;
import com.myk.game.sumeru.interfaces.IGameButtonModel;
import com.myk.game.sumeru.interfaces.IGameUI;
import com.myk.game.sumeru.databinding.PageGameBinding;
import com.myk.game.sumeru.interfaces.IMainController;
import com.myk.game.lib.base.AbsBasePage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 游戏页
 */
public class GamePage extends AbsBasePage<PageGameBinding> implements IGameUI {

    private final IMainController controller; //应用接口
    private final Map<String, Bitmap> allChessImages; //棋子的图片
    private IGame game; //游戏环境对象
    private float boardWidth; //棋盘宽度
    private float boardHeight; //棋盘高度
    private int mapRow; //棋盘行数
    private int mapCol; //棋盘列数
    private float unitSize; //根据宽度和列数和边距等比划分的单位距离
    private float unitOffset; //边距尺寸
    private float gridStrokeSize; //单元格子线框的尺寸
    private float gridOffset; //单元格子内切于线框需要的偏移距离
    private float gridUnitSize; //单元格子实际尺寸
    private float chessSize; //棋子的直径
    private List<Chess> othSlotData; //棋槽对象容器
    private List<Chess> ownSlotData; //棋槽对象容器

    public GamePage(@NonNull Context context) {
        super(context);
        this.controller = (IMainController) context;
        this.allChessImages = new HashMap<>();
        binding.chessBoardView.post(() -> game.init(GamePage.this));
    }

    /**
     * 设置游戏模式
     */
    public void chooseMode(Class<?> gameMode) {
        if (Objects.equals(gameMode, PersonalGame.class)) {
            game = new PersonalGame();
        }
        else if (Objects.equals(gameMode, RobotGame.class)) {
            game = new RobotGame();
        }
    }

    @Override
    public void initChessBoard() {
        calculateParameters();
        adjustViewSize();
        drawBoardBg();
        drawBoardChesses();
        drawGameTips();
        initAnimeLayer();
        listenChessBoardTouchEvent();
        setChessSlotAdapter();
        listenSlotTouchEvent();
    }

    //计算棋盘绘制和交互相关的参数
    private void calculateParameters() {
        //设置棋盘背景
        boardWidth = binding.chessBoardView.getWidth();
        boardHeight = binding.chessBoardView.getHeight();
        mapRow = game.getMap().getRowCount();
        mapCol = game.getMap().getColumnCount();
        unitSize = boardWidth / (mapCol + 1);
        unitOffset = unitSize / 2;
        gridStrokeSize = boardWidth / 480;
        gridOffset = gridStrokeSize / 2;
        gridUnitSize = unitSize - gridOffset * 2;
        chessSize = gridUnitSize - gridStrokeSize * 2; //棋子直径（刚好和线框内切）
    }

    //调整视图尺寸
    private void adjustViewSize() {
        binding.tvBtnA.setTextSize(TypedValue.COMPLEX_UNIT_PX, binding.tvBtnA.getHeight() / 2f);
        binding.tvBtnB.setTextSize(TypedValue.COMPLEX_UNIT_PX, binding.tvBtnB.getHeight() / 2f);
        binding.tvBtnC.setTextSize(TypedValue.COMPLEX_UNIT_PX, binding.tvBtnC.getHeight() / 2f);
        binding.tvBtnD.setTextSize(TypedValue.COMPLEX_UNIT_PX, binding.tvBtnD.getHeight() / 2f);
        binding.tvGameTip.setTextSize(TypedValue.COMPLEX_UNIT_PX, binding.tvBtnA.getHeight() / 2f);
    }

    //绘制棋盘背景
    private void drawBoardBg() {
        //绘制棋盘和棋槽的图片背景
        Bitmap bgBitmap = BitmapUtil.getBitmap(context, R.drawable.bg_chessboard, boardWidth, boardHeight);
        Drawable boardBg = getChessBoardBgDrawable(bgBitmap);
        binding.chessBoardView.setBackground(boardBg);
        Drawable slotBg = getChessBoardBgDrawable(bgBitmap);
        binding.rcvOthChessSlot.setBackground(slotBg);
        binding.rcvOwnChessSlot.setBackground(slotBg);
        //绘制游戏格子地图
        Bitmap gridsBitmap = getMapGridBitmap();
        binding.chessBoardView.addDrawElement((canvas, paint) -> canvas.drawBitmap(gridsBitmap, 0, 0, paint));
    }

    //获取棋盘背景图
    private Drawable getChessBoardBgDrawable(Bitmap bgBitmap) {
        //设置棋盘背景
        return new ShapeDrawable(new Shape() {
            @Override
            public void draw(Canvas canvas, Paint paint) {
                //画背景图片
                float w = canvas.getWidth();
                float h = canvas.getHeight();
                float r = w / 48;
                int id = canvas.saveLayer(0, 0, w, h, paint, Canvas.ALL_SAVE_FLAG);
                paint.setAntiAlias(true);
                paint.setDither(true);
                paint.setStyle(Paint.Style.FILL);
                paint.setColor(Color.BLACK);
                canvas.drawRoundRect(0, 0, w, h, r, r, paint);
                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
                canvas.drawBitmap(bgBitmap, 0, 0, paint);
                paint.setXfermode(null);
                canvas.restoreToCount(id);
                //画黑色边框
                float stroke = w / 240;
                float offset = stroke / 2;
                paint.setStyle(Paint.Style.STROKE);
                paint.setStrokeWidth(stroke);
                paint.setColor(Color.BLACK);
                canvas.drawRoundRect(offset, offset, w - offset, h - offset, r, r, paint);
            }
        });
    }

    //获取绘制好的地图图片
    private Bitmap getMapGridBitmap() {
        return new DrawBuffer((int) boardWidth, (int) boardHeight) {
            @Override
            public void onDraw(Canvas bufferCanvas, Paint bufferPaint) {
                bufferCanvas.translate(unitOffset, unitOffset);
                //绘制格子
                Grid[][] grids = game.getMap().getGrids();
                for (int row = 0; row < mapRow; row++) {
                    for (int col = 0; col < mapCol; col++) {
                        float left = col * unitSize + gridOffset;
                        float top = row * unitSize + gridOffset;
                        float right = left + gridUnitSize;
                        float bottom = top + gridUnitSize;
                        int type = grids[row][col].getType();
                        drawGrid(type, left, top, right, bottom, bufferCanvas, bufferPaint);
                    }
                }
            }
        }.getBufferBitmap();
    }

    //根据横纵坐标绘制格子
    private void drawGrid(int type, float left, float top, float right, float bottom, Canvas canvas, Paint paint) {
        float w = canvas.getWidth();
        float round = w / 96;
        paint.setStyle(Paint.Style.FILL);
        if (type == 1 || type == 9) {
            paint.setColor(0x99582E0F);
        }
        else if (type == 2 || type == 8) {
            paint.setColor(0x99385E0F);
        }
        else if (type == 5) {
            paint.setColor(0x99085E9F);
        }
        else {
            paint.setColor(0x99EFEFDF);
        }
        canvas.drawRoundRect(left, top, right, bottom, round, round, paint);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(gridStrokeSize);
        paint.setColor(0x66666666);
        canvas.drawRoundRect(left, top, right, bottom, round, round, paint);
    }

    //绘制棋盘上的棋子
    private void drawBoardChesses() {
        binding.chessBoardView.addDrawElement((canvas, paint) -> {
            List<Chess> allChesses = new ArrayList<>();
            List<Chess> othChesses = game.getChesses(Chess.OTH);
            List<Chess> ownChesses = game.getChesses(Chess.OWN);
            List<Chess> midChesses = game.getChesses(Chess.MID);
            allChesses.addAll(othChesses);
            allChesses.addAll(ownChesses);
            allChesses.addAll(midChesses);
            paint.setAntiAlias(true);
            paint.setDither(true);
            paint.setFilterBitmap(true);
            canvas.translate(unitOffset, unitOffset);

            for (Chess chess : allChesses) {
                Grid pos = chess.getPosition();
                if (pos != null) { //棋子落在棋盘上了
                    float chessX = pos.getX() * unitSize + gridOffset * 3; //根据棋子当前的坐标算出横坐标
                    float chessY = pos.getY() * unitSize + gridOffset * 3;//根据棋子当前的坐标算出纵坐标
                    //绘制棋子插画
                    Bitmap chessBitmap = getChessImageBitmap(chess);
                    canvas.drawBitmap(chessBitmap, chessX, chessY, paint);
                    drawChessNumber(canvas, paint, chess, chessX, chessY);
                }
            }
            canvas.translate(-unitOffset, -unitOffset);
        });
    }

    //获取棋子绘图
    private Bitmap getChessImageBitmap(Chess chess) {
        String key = chess.NAME + chess.getParty();
        Bitmap bitmap = allChessImages.get(key);
        if (bitmap == null) {
            bitmap = new DrawBuffer((int) chessSize, (int) chessSize) {
                @Override
                public void onDraw(Canvas bufferCanvas, Paint bufferPaint) {
                    //先画背景
                    if (chess.getParty() == Chess.MID) {
                        bufferCanvas.drawBitmap(controller.getImageDataPool().getResBitmap(R.drawable.bg_chess_mid, (int) chessSize, (int) chessSize), 0, 0, bufferPaint);
                    }
                    else if (chess.getParty() == Chess.OWN) {
                        bufferCanvas.drawBitmap(controller.getImageDataPool().getResBitmap(R.drawable.bg_chess_own, (int) chessSize, (int) chessSize), 0, 0, bufferPaint);
                    }
                    else if (chess.getParty() == Chess.OTH) {
                        bufferCanvas.drawBitmap(controller.getImageDataPool().getResBitmap(R.drawable.bg_chess_oth, (int) chessSize, (int) chessSize), 0, 0, bufferPaint);
                    }
                    //再画插画
                    bufferCanvas.drawBitmap(controller.getImageDataPool().getResBitmap(chess.RES, (int) chessSize, (int) chessSize), 0, 0, bufferPaint);
                }
            }.getBufferBitmap();
            allChessImages.put(key, bitmap);
        }
        return bitmap;
    }

    //绘制棋子数值
    private void drawChessNumber(Canvas canvas, Paint paint, Chess chess, float chessX, float chessY) {
        float textSize = chessSize * 0.16f;
        float textY = chessY + chessSize * 0.80f;
        paint.setTextSize(textSize);
        paint.setFakeBoldText(true);
        //绘制移速数值
        float velocityX = chessX + chessSize * 0.2455f;
        paint.setColor(chess.getVelocityColor());
        canvas.drawText(String.valueOf(chess.getVelocity()), velocityX, textY, paint);
        //绘制战力数值
        float strengthX = chessX + chessSize * 0.651f;
        paint.setColor(chess.getStrengthColor());
        canvas.drawText(String.valueOf(chess.getStrength()), strengthX, textY, paint);
    }

    //初始化动画层
    private void initAnimeLayer() {
        //++初始化动画层
    }

    //监听棋盘交互事件
    private void listenChessBoardTouchEvent() {
        binding.chessBoardView.setOnTouchListener(new OnTouchListener() {
            private float dX, dY, uX, uY;   //触摸事件按下抬起时的点
            private long dT, uT; //触摸事件按下抬起的时间

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    dX = event.getX();
                    dY = event.getY();
                    dT = System.currentTimeMillis();
                }
                else if (event.getAction() == MotionEvent.ACTION_UP) {
                    uX = event.getX();
                    uY = event.getY();
                    uT = System.currentTimeMillis();
                    handleEvent();
                }
                return true;
            }

            //处理触摸事件
            private void handleEvent() {
                if (getDistance(dX, dY, uX, uY) > unitSize) {
                    return; //移动距离超过一格视为放弃落子
                }
                if ((uT - dT) < 50) {
                    return; //触摸时间过短视为误触
                }
                if (checkEventRange()) {
                    int[] coordinate = getCoordinateByPoint();
                    int pCol = coordinate[0];
                    int pRow = coordinate[1];
                    processChessBoardGridClickAction(pCol, pRow);
                }
            }

            //获取两点之间的距离
            private float getDistance(float x0, float y0, float x1, float y1) {
                float a = (y0 - y1) * (y0 - y1) + (x0 - x1) * (x0 - x1);
                return (float) Math.sqrt(a);
            }

            //判断点击事件是否在有效范围内
            private boolean checkEventRange() {
                float minX = unitOffset;
                float maxX = boardWidth - unitSize;
                float minY = unitOffset;
                float maxY = boardHeight - unitSize;
                return uX > minX && uX < maxX && uY > minY && uY < maxY;
            }

            //根据点击事件获取坐标
            private int[] getCoordinateByPoint() {
                int[] c = new int[2];
                int x = (int) ((uX - unitOffset) / unitSize);
                int y = (int) ((uY - unitOffset) / unitSize);
                c[0] = x;
                c[1] = y;
                return c;
            }

        });
    }

    //处理棋盘格子按下事件
    private void processChessBoardGridClickAction(int col, int row) {
        Grid grid = game.getMap().getGrids()[row][col];
        Chess chess = grid.getChess();
        if (chess != null) {
            chess.notifyBeClickEvent();
        }
        else {
            grid.notifyBeClickEvent();
        }
    }

    //设置棋槽的适配器
    private void setChessSlotAdapter() {
        othSlotData = new ArrayList<>();
        ownSlotData = new ArrayList<>();
        Paint slotPaint = new Paint();
        slotPaint.setAntiAlias(true);
        slotPaint.setDither(true);
        slotPaint.setFilterBitmap(true);
        binding.rcvOthChessSlot.setAdapter(new SimpleAdapter<Chess>(othSlotData, R.layout.item_slot_chess) {
            @Override
            public void convert(VH holder, int viewPosition, Chess data, int dataPosition) {
                holder.itemView.setBackground(getSlotChessImgDrawable(slotPaint, data));
            }
        });
        binding.rcvOwnChessSlot.setAdapter(new SimpleAdapter<Chess>(ownSlotData, R.layout.item_slot_chess) {
            @Override
            public void convert(VH holder, int viewPosition, Chess data, int dataPosition) {
                holder.itemView.setBackground(getSlotChessImgDrawable(slotPaint, data));
            }
        });
    }

    //获取棋槽上的棋子图片
    private Drawable getSlotChessImgDrawable(Paint paint, Chess chess) {
        return new BitmapDrawable(getResources(), getChessImageBitmap(chess)) {
            @Override
            public void draw(Canvas canvas) {
                super.draw(canvas);
                float textSize = chessSize * 0.16f;
                float textY = chessSize * 0.90f;
                paint.setTextSize(textSize);
                paint.setFakeBoldText(true);
                //绘制移速数值
                float velocityX = chessSize * 0.265f;
                paint.setColor(chess.getVelocityColor());
                canvas.drawText(String.valueOf(chess.getVelocity()), velocityX, textY, paint);
                //绘制战力数值
                float strengthX = chessSize * 0.735f;
                paint.setColor(chess.getStrengthColor());
                canvas.drawText(String.valueOf(chess.getStrength()), strengthX, textY, paint);
            }
        };
    }

    //++绘制游戏的提示图标
    private void drawGameTips() {

    }

    //监听棋槽的触摸事件
    private void listenSlotTouchEvent() {
        //定义棋槽的拖拽事件
        class SlopItemTouchHelperCallback extends ItemTouchHelper.Callback {

            private final List<Chess> chessList;
            private int fromPos;
            private int toPos;

            private float startX;
            private float startY;

            public SlopItemTouchHelperCallback(List<Chess> chesses) {
                this.chessList = chesses;
            }

            @Override
            public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
                super.onSelectedChanged(viewHolder, actionState);
                if (viewHolder != null) {
                    //获取初始值
                    startX = viewHolder.itemView.getX();
                    startY = viewHolder.itemView.getY();
                    //重置初始值
                    fromPos = 0;
                    toPos = 0;
                    //LogUtils.e("startX:" + startX + ",startY:" + startY);
                }
            }

            @Override
            public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
                int dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;    //拖动标记
                int swipeFlags = 0;    //滑动标记
                return makeMovementFlags(dragFlag, swipeFlags);//通过makeMovementFlags生成最终结果
            }

            @Override
            public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
                this.fromPos = viewHolder.getAbsoluteAdapterPosition();
                this.toPos = target.getAbsoluteAdapterPosition();
                return true;
            }

            @Override
            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            }

            @Override
            public boolean isLongPressDragEnabled() {
                return false; //为了实现不用长按就能拖拽，这里必须为false
            }

            @Override
            public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
                float w = viewHolder.itemView.getWidth();
                float h = viewHolder.itemView.getHeight();
                float x = viewHolder.itemView.getX();
                float y = viewHolder.itemView.getY();
                float diffX = Math.abs(startX - x);
                float diffY = Math.abs(startY - y);
                //LogUtils.e("w:" + w + ",h:" + h + ",x:" + x + ",y:" + y + ",index:" + index);
                //判断是否为交换位置
                if (diffX > w && y > -h / 2 && y < h / 2) { //棋子拖拽没有超过棋槽的上下分界
                    if (fromPos != toPos) {
                        chessList.add(toPos, chessList.remove(fromPos));
                        recyclerView.getAdapter().notifyDataSetChanged();
                    }
                }
                //判断是否为点击
                if (diffX < w / 10 && diffY < h / 10) {
                    int index = viewHolder.getLayoutPosition();
                    chessList.get(index).notifyBeClickEvent(); //触发棋子点击事件
                }
                super.clearView(recyclerView, viewHolder);
            }
        }
        SlopItemTouchHelperCallback othItemTouchHelperCallback = new SlopItemTouchHelperCallback(othSlotData);
        ItemTouchHelper othSlopItemTouchHelper = new ItemTouchHelper(othItemTouchHelperCallback);
        binding.rcvOthChessSlot.addOnItemTouchListener(new OnRecyclerItemDownListener(binding.rcvOthChessSlot) {
            @Override
            public void onItemDown(RecyclerView.ViewHolder vh) {
                othSlopItemTouchHelper.startDrag(vh); //设置列表项按下时开始可以拖拽
            }
        });
        othSlopItemTouchHelper.attachToRecyclerView(binding.rcvOthChessSlot);
        binding.rcvOthChessSlot.getItemAnimator().setAddDuration(0);
        binding.rcvOthChessSlot.getItemAnimator().setChangeDuration(0);
        binding.rcvOthChessSlot.getItemAnimator().setMoveDuration(0);
        binding.rcvOthChessSlot.getItemAnimator().setRemoveDuration(0);
        SlopItemTouchHelperCallback ownItemTouchHelperCallback = new SlopItemTouchHelperCallback(ownSlotData);
        ItemTouchHelper ownSlopItemTouchHelper = new ItemTouchHelper(ownItemTouchHelperCallback);
        binding.rcvOwnChessSlot.addOnItemTouchListener(new OnRecyclerItemDownListener(binding.rcvOwnChessSlot) {
            @Override
            public void onItemDown(RecyclerView.ViewHolder vh) {
                ownSlopItemTouchHelper.startDrag(vh);
            }
        });
        ownSlopItemTouchHelper.attachToRecyclerView(binding.rcvOwnChessSlot);
        binding.rcvOwnChessSlot.getItemAnimator().setAddDuration(0);
        binding.rcvOwnChessSlot.getItemAnimator().setChangeDuration(0);
        binding.rcvOwnChessSlot.getItemAnimator().setMoveDuration(0);
        binding.rcvOwnChessSlot.getItemAnimator().setRemoveDuration(0);
    }

    @Override
    public void refreshChessBoard() {
        binding.chessBoardView.postInvalidate();
        othSlotData = game.getChesses(Chess.OTH);
        ((SimpleAdapter<Chess>) binding.rcvOthChessSlot.getAdapter()).setDatas(othSlotData);
        ownSlotData = game.getChesses(Chess.OWN);
        ((SimpleAdapter<Chess>) binding.rcvOwnChessSlot.getAdapter()).setDatas(ownSlotData);
    }

    @Override
    public void setGameButtons(IGameButtonModel... buttonModels) {
        TextView[] btnViews = {binding.tvBtnA, binding.tvBtnB, binding.tvBtnC, binding.tvBtnD};
        for (int i = 0; i < btnViews.length; i++) {
            TextView btnView = btnViews[i];
            if (i < buttonModels.length){
                IGameButtonModel btnModel = buttonModels[i];
                btnView.setText(btnModel.getButtonText());
                btnView.setOnClickListener(v -> btnModel.getButtonEvent().run());
                btnView.setVisibility(VISIBLE);
            }
            else {
                btnView.setText("");
                btnView.setOnClickListener(null);
                btnView.setVisibility(INVISIBLE);
            }
        }
    }

    @Override
    public void leave() {
        jumpPageTo(HomePage.class);
    }

    @Override
    public void showTip(String tip) {
        binding.tvGameTip.setText(tip);
    }

}
